#!/bin/bash

function down_fabric_cluster() {
    # down fabric network
    echo -n "down fabric network ... "
    for i in {0..3}
    do
        ssh node$i "cd $GOPATH/src/fabric-sdk/gen_crypto
                    docker-compose -f docker-compose-${i}.yaml down -v > /dev/null 2>&1
        " &
    done
    wait
    echo "done"
}

function wait_5s() {
    for((i=1; i<=5; i++))
    do
        sleep 1s
        echo "wait ${i}s for raft leader election ..."
    done
}

function gen_join_channel() {
    # generate channel
    docker exec cli0 peer channel create -o orderer0.demo.com:7050 -c mychannel -f ./channel-artifacts/channel.tx \
    --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/demo.com/orderers/orderer0.demo.com/msp/tlscacerts/tlsca.demo.com-cert.pem
    if [ $? -ne 0 ]; then
        echo "no Raft leader"
        return -1
    fi

    # join for cli0/peer0.org1.demo.com
    docker exec cli0 peer channel join -b mychannel.block
    docker exec cli0 peer channel update -o orderer0.demo.com:7050 -c mychannel -f ./channel-artifacts/Org1MSPanchors.tx \
    --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/demo.com/orderers/orderer0.demo.com/msp/tlscacerts/tlsca.demo.com-cert.pem

    # copy to local host & cli1/peer1.org1.demo.com
    docker cp cli0:/opt/gopath/src/github.com/hyperledger/fabric/peer/mychannel.block $GOPATH/src/fabric-sdk/gen_crypto/mychannel.block
    docker cp $GOPATH/src/fabric-sdk/gen_crypto/mychannel.block cli1:/opt/gopath/src/github.com/hyperledger/fabric/peer/mychannel.block

    # join for cli1/peer1.org1.demo.com
    docker exec cli1 peer channel join -b mychannel.block

    # copy mychannel.block to docker containers & join for cli{0..1}/peer{0..1}.org{2..4}.demo.com
    for i in {1..3}
    do
        let j=i+1
        scp $GOPATH/src/fabric-sdk/gen_crypto/mychannel.block node${i}:$GOPATH/src/fabric-sdk/gen_crypto/mychannel.block
        ssh node$i "
            docker cp $GOPATH/src/fabric-sdk/gen_crypto/mychannel.block cli0:/opt/gopath/src/github.com/hyperledger/fabric/peer/mychannel.block
            docker cp $GOPATH/src/fabric-sdk/gen_crypto/mychannel.block cli1:/opt/gopath/src/github.com/hyperledger/fabric/peer/mychannel.block
            docker exec cli0 peer channel join -b mychannel.block
            docker exec cli1 peer channel join -b mychannel.block
            docker exec cli0 peer channel update -o orderer0.demo.com:7050 -c mychannel -f ./channel-artifacts/Org${j}MSPanchors.tx --tls \
            --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/demo.com/orderers/orderer0.demo.com/msp/tlscacerts/tlsca.demo.com-cert.pem
        "
    done
    return 0
}

function clone_fabric_sdk() {
    echo -n "clone fabric-sdk to node{1..3} ... "
    for i in {1..3}
    do
        ssh node$i "
            cd $GOPATH/src
            if [ ! -d "fabric-sdk" ]; then
                git clone -q https://gitee.com/czy233/fabric-sdk.git $GOPATH/src/fabric-sdk
                cd fabric-sdk
                git checkout regEvent
            else
                cd ./fabric-sdk
                git checkout regEvent
                git pull
            fi
        " &
    done
    wait
    echo "done"
}

function install_chaincode() {
    # copy chaincode to cli0
    cd $GOPATH/src/fabric-sdk/chaincode/go/
    if [ ! -f "objhash_chaincode.go" ]; then
        echo "no chaincode exist, please put chaincode to $(pwd)"
        exit -1
    fi

    # set docker go env
    docker exec cli0 bash -c "go env -w GOPROXY=https://goproxy.io,direct; go env -w GO111MODULE=on; go env -w GOFLAGS=\" -mod=vendor\""
    cd $GOPATH/src/fabric-sdk/chaincode/
    if [ ! -f "go.mod" ]; then
        docker exec cli0 bash -c "cd /opt/gopath/src/github.com/hyperledger/multiple-deployment/chaincode/; go mod init go"
    fi
    if [ ! -d "vendor" ]; then
        docker exec cli0 bash -c "cd /opt/gopath/src/github.com/hyperledger/multiple-deployment/chaincode/; go mod vendor"
    fi

    # package chaincode
    docker exec cli0 peer lifecycle chaincode package ./channel-artifacts/mycc.tar.gz --path /opt/gopath/src/github.com/hyperledger/multiple-deployment/chaincode/go/ --lang golang --label mycc

    # copy chaincode.tar.gz to other peers
    sudo chown $USER:$USER $GOPATH/src/fabric-sdk/gen_crypto/channel-artifacts/mycc.tar.gz
    for i in {1..3}
    do
        scp $GOPATH/src/fabric-sdk/gen_crypto/channel-artifacts/mycc.tar.gz node${i}:$GOPATH/src/fabric-sdk/gen_crypto/channel-artifacts/mycc.tar.gz &
    done
    wait

    # install chaincode for all peers
    for i in {0..3}
    do
        ssh node$i "cd $GOPATH/src/fabric-sdk/gen_crypto
                    docker exec cli0 peer lifecycle chaincode install ./channel-artifacts/mycc.tar.gz
                    docker exec cli1 peer lifecycle chaincode install ./channel-artifacts/mycc.tar.gz
        " &
    done
    wait
    # docker exec cli0 peer lifecycle chaincode queryinstalled
}

function approve_chaincode() {
    # get chaincode package ID
    str=`docker exec cli0 peer lifecycle chaincode queryinstalled | grep mycc`
    strA=${str#*ID: } 
    id=${strA%,*}
    echo "packageID="$id

    # approve chaincode for org
    for i in {0..3}
    do
        ssh node$i "
            docker exec cli0 peer lifecycle chaincode approveformyorg --ordererTLSHostnameOverride orderer0.demo.com \
            --channelID mychannel --name mycc --version 1.0 --package-id $id --sequence 1 --tls \
            --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/demo.com/orderers/orderer0.demo.com/msp/tlscacerts/tlsca.demo.com-cert.pem
        " &
    done
    wait

    # chaincode query already approved
    # docker exec cli0 peer lifecycle chaincode queryapproved --channelID mychannel  --name mycc --sequence 1 -O json

    # check chaincode status
    docker exec cli0 peer lifecycle chaincode checkcommitreadiness --channelID mychannel --name mycc --version 1.0 --sequence 1 --tls \
    --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/demo.com/orderers/orderer0.demo.com/msp/tlscacerts/tlsca.demo.com-cert.pem --output json
}

function commit_chaincode() {
    # commit chaincode
    docker exec cli1 peer lifecycle chaincode commit -o orderer0.demo.com:7050 --channelID mychannel --name mycc --version 1.0 --sequence 1 --tls true \
    --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/demo.com/orderers/orderer0.demo.com/msp/tlscacerts/tlsca.demo.com-cert.pem \
    --peerAddresses peer0.org1.demo.com:7051 \
    --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.demo.com/peers/peer0.org1.demo.com/tls/ca.crt \
    --peerAddresses peer0.org2.demo.com:7051 \
    --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.demo.com/peers/peer0.org2.demo.com/tls/ca.crt \
    --peerAddresses peer0.org3.demo.com:7051 \
    --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org3.demo.com/peers/peer0.org3.demo.com/tls/ca.crt \
    --peerAddresses peer0.org4.demo.com:7051 \
    --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org4.demo.com/peers/peer0.org4.demo.com/tls/ca.crt

    # querycommitted chaincode 
    docker exec cli0 peer lifecycle chaincode querycommitted --channelID mychannel --name mycc \
    --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/demo.com/orderers/orderer0.demo.com/msp/tlscacerts/tlsca.demo.com-cert.pem

    # invoke chaincode
    docker exec cli0 peer chaincode invoke -o orderer0.demo.com:7050 --ordererTLSHostnameOverride orderer0.demo.com --tls \
    --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/demo.com/orderers/orderer0.demo.com/msp/tlscacerts/tlsca.demo.com-cert.pem \
    -C mychannel -n mycc \
    --peerAddresses peer0.org1.demo.com:7051 \
    --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.demo.com/peers/peer0.org1.demo.com/tls/ca.crt \
    --peerAddresses peer0.org2.demo.com:7051 \
    --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.demo.com/peers/peer0.org2.demo.com/tls/ca.crt \
    --peerAddresses peer0.org3.demo.com:7051 \
    --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org3.demo.com/peers/peer0.org3.demo.com/tls/ca.crt \
    --peerAddresses peer0.org4.demo.com:7051 \
    --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org4.demo.com/peers/peer0.org4.demo.com/tls/ca.crt \
    -c '{"function":"initLedger","Args":[]}'

    # invoke chaincode
    docker exec cli0 peer chaincode invoke -o orderer0.demo.com:7050 --ordererTLSHostnameOverride orderer0.demo.com --tls \
    --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/demo.com/orderers/orderer0.demo.com/msp/tlscacerts/tlsca.demo.com-cert.pem \
    -C mychannel -n mycc \
    --peerAddresses peer0.org1.demo.com:7051 \
    --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.demo.com/peers/peer0.org1.demo.com/tls/ca.crt \
    --peerAddresses peer0.org2.demo.com:7051 \
    --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.demo.com/peers/peer0.org2.demo.com/tls/ca.crt \
    --peerAddresses peer0.org3.demo.com:7051 \
    --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org3.demo.com/peers/peer0.org3.demo.com/tls/ca.crt \
    --peerAddresses peer0.org4.demo.com:7051 \
    --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org4.demo.com/peers/peer0.org4.demo.com/tls/ca.crt \
    -c '{"function":"CreateObject","Args":["obj_1","123"]}'

    # query ledger
    docker exec cli0 peer chaincode query -C mychannel -n mycc -c '{"Args":["ReadObject","obj_1"]}'
    # docker exec cli0 peer chaincode query -C mychannel -n mycc -c '{"Args":["ReadObject","obj_1"]}'
}

source /etc/profile

# GOPATH exist ?
if [ 0"$GOPATH" = "0" ]; then
    echo "GOPATH not exist, please install go and set it"
    exit -1
fi
# clone fabric-sdk from git
cd $GOPATH/src
if [ ! -d "fabric-sdk" ]; then
    git clone https://gitee.com/czy233/fabric-sdk.git $GOPATH/src/fabric-sdk
    cd fabric-sdk
    git checkout regEvent
else
    cd ./fabric-sdk
    git checkout regEvent
    git pull 
fi

# crypto config files exist ?
cd $GOPATH/src/fabric-sdk/gen_crypto
if [[ ! -d "channel-artifacts" || ! -d "crypto-config" ]]; then
    echo "'crypto-config' & 'channel-artifacts' not exist"
    echo "please gen-crypto by hand && push it to fabric-sdk"
    exit -1
fi

# clone fabric-sdk to node{1..3}
clone_fabric_sdk

# config hosts in every host
echo -n "config hosts ... "
for i in {0..3}
do
    ssh node$i "cd $GOPATH/src/fabric-sdk/; ./hosts_config.sh > /dev/null 2>&1" &
done
wait
echo "done"

# start fabric network
echo "start fabric network"
down_fabric_cluster  # remove fabric containers may exist
for i in {0..3}
do
    ssh node$i "cd $GOPATH/src/fabric-sdk/gen_crypto
                docker-compose -f docker-compose-${i}.yaml up -d
    " &
done
wait
echo "finish start fabric network!"

# wait for a few time wait raft leader election
wait_5s

# generate & join channel for all peers
gen_join_channel
if [ $? -ne 0 ]; then
    echo "generate & join channel error"
    exit -1
fi

# install chaincode
install_chaincode

# approve chaincode
approve_chaincode

# commit chaincode
commit_chaincode
